package com.shopping.mall.core.module.paypal.service.impl;


import com.paypal.api.payments.*;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import com.shopping.mall.auth.utils.UserUtils;
import com.shopping.mall.base.http.ResponseState;
import com.shopping.mall.base.http.Result;
import com.shopping.mall.base.state.OrderState;
import com.shopping.mall.core.module.order.entity.Order;
import com.shopping.mall.core.module.order.mapper.OrderMapper;
import com.shopping.mall.core.module.order.service.StockService;
import com.shopping.mall.core.module.paypal.config.PaypalConfig;
import com.shopping.mall.core.module.paypal.entity.PaymentModel;
import com.shopping.mall.core.module.paypal.entity.PaypalPaymentIntent;
import com.shopping.mall.core.module.paypal.entity.PaypalPaymentMethod;
import com.shopping.mall.core.module.paypal.service.PaymentService;
import com.shopping.mall.core.module.saleData.service.SaleDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @program: 
 * @description:
 * @author: 
 * @create: 
 **/
@Service
public class PaymentServiceImpl implements PaymentService {

    @Autowired
    private PaypalConfig paypalConfig;

    private final String USD = "USD";


    @Autowired
    private StockService stockService;


    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private SaleDataService saleDataService;


    @Transactional
    @Override
    public Payment createPayment(PaymentModel paymentModel , String cancelUrl, String successUrl) throws PayPalRESTException, UnsupportedEncodingException {

        //订单金额 以及金额类型 默认为USD
        Amount amount = new Amount();
        if(null!=paymentModel.getCurrency()){
            amount.setCurrency(paymentModel.getCurrency());
        }else{
            amount.setCurrency(USD);
        }
        amount.setTotal(paymentModel.getAmount());

        List<Transaction> transactions = new ArrayList<>();
        Transaction transaction = new Transaction();
        transaction.setDescription(paymentModel.getDescription());
        transaction.setAmount(amount);
        transactions.add(transaction);

        /**
         * 支付信息
         */
        Payer payer = new Payer();
        payer.setPaymentMethod(PaypalPaymentMethod.paypal.toString());
        Payment payment = new Payment();
        payment.setIntent(PaypalPaymentIntent.sale.toString());
        payment.setPayer(payer);
        payment.setTransactions(transactions);
        /**
         * 回调地址
         */
        RedirectUrls redirectUrls = new RedirectUrls();
        redirectUrls.setCancelUrl(cancelUrl);
        redirectUrls.setReturnUrl(successUrl);
        payment.setRedirectUrls(redirectUrls);
        return payment.create(paypalConfig.apiContext());
    }

    @Transactional
    @Override
    public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException, UnsupportedEncodingException {
        Payment payment = new Payment();
        payment.setId(paymentId);
        PaymentExecution paymentExecute = new PaymentExecution();
        paymentExecute.setPayerId(payerId);
        return payment.execute(paypalConfig.apiContext(), paymentExecute);
    }

    @Transactional
    @Override
    public Result<Object> refund(Order order){

        Order oldOrder=orderMapper.selectById(order.getId());

        if(oldOrder==null){
            return Result.error(ResponseState.ORDER_NOT_EXIST.getValue(),ResponseState.ORDER_NOT_EXIST.getMessage());
        }
        //退款人id验证
//        if(!oldOrder.getUserId().equals(UserUtils.getLoginUserId())){
//            return Result.error(ResponseState.ERROR.getValue(), ResponseState.ERROR.getMessage());
//        }
        if(oldOrder.getState()!= OrderState.COPY_SUCCESS.getValue()&&order.getState()!=OrderState.CHECK.getValue()){
            return Result.error(ResponseState.ORDER_NOT_MATCH.getValue(),ResponseState.ORDER_NOT_MATCH.getMessage());
        }



        PaymentModel paymentModel = new PaymentModel();
        //金额
        paymentModel.setAmount(String.valueOf(oldOrder.getTotalPrice()));
        //金额类型
        paymentModel.setCurrency("USD");
        //充值描述
        paymentModel.setDescription("payment description");
        // ###Sale
        // A sale transaction.
        // Create a Sale object with the
        // given sale transaction id.

        // ###Refund
        // A refund transaction.
        // Use the amount to create
        // a refund object
        RefundRequest refund = new RefundRequest();
        // ###Amount
        // Create an Amount object to
        // represent the amount to be
        // refunded. Create the refund object, if the refund is partial
        Amount amount=new Amount();
        if(null!=paymentModel.getCurrency()){
            amount.setCurrency(paymentModel.getCurrency());
        }else{
            amount.setCurrency(USD);
        }
        amount.setTotal(paymentModel.getAmount());

        refund.setAmount(amount);
        refund.setReason("用户取消订单");

        try {
//            if(request.getSaleId() == null) {
                //注意这段代码，获取saleId
                Payment payment = Payment.get(paypalConfig.apiContext(), oldOrder.getOutTradeNo());
                Transaction transaction = payment.getTransactions().get(0);
                RelatedResources resources = transaction.getRelatedResources().get(0);
                String id = resources.getSale().getId();
//                request.setSaleId(id);
//            }
//
            // ### Api Context
            // Pass in a `ApiContext` object to authenticate
            // the call and to send a unique request id
            // (that ensures idempotency). The SDK generates
            // a request id if you do not pass one explicitly.

            // Refund by posting to the APIService
            // using a valid AccessToken
            Sale sale = new Sale();
            sale.setId(id);
            DetailedRefund res = sale.refund(paypalConfig.apiContext(), refund);
            System.out.println(res);
//            PaypalRefundReturn r = new PaypalRefundReturn();
//            r.setState(res.getState());
//            r.setAmount(res.getAmount().getTotal());
//            r.setCurrency(res.getAmount().getCurrency());
//            return r;
            oldOrder.setState(OrderState.ORDER_CANCEL.getValue());
            oldOrder.setFinishAt(new Timestamp(new Date().getTime()));
            orderMapper.updateById(oldOrder);
            saleDataService.refund(oldOrder);
            stockService.addStock(oldOrder.getGoods());
            return Result.OK();
        } catch (PayPalRESTException | UnsupportedEncodingException e) {
            return Result.error(ResponseState.REFUND_ERROR.getValue(),ResponseState.REFUND_ERROR.getMessage());
        }
    }

    @Transactional
    @Override
    public Result<Object> refundAdmin(Order order){

        Order oldOrder=orderMapper.selectById(order.getId());

        if(oldOrder==null){
            return Result.error(ResponseState.ORDER_NOT_EXIST.getValue(),ResponseState.ORDER_NOT_EXIST.getMessage());
        }
        if(oldOrder.getState()!= OrderState.COPY_SUCCESS.getValue()){
            return Result.error(ResponseState.ORDER_NOT_MATCH.getValue(),ResponseState.ORDER_NOT_MATCH.getMessage());
        }



        PaymentModel paymentModel = new PaymentModel();
        //金额
        paymentModel.setAmount(String.valueOf(oldOrder.getTotalPrice()));
        //金额类型
        paymentModel.setCurrency("USD");
        //充值描述
        paymentModel.setDescription("payment description");
        // ###Sale
        // A sale transaction.
        // Create a Sale object with the
        // given sale transaction id.

        // ###Refund
        // A refund transaction.
        // Use the amount to create
        // a refund object
        RefundRequest refund = new RefundRequest();
        // ###Amount
        // Create an Amount object to
        // represent the amount to be
        // refunded. Create the refund object, if the refund is partial
        Amount amount=new Amount();
        if(null!=paymentModel.getCurrency()){
            amount.setCurrency(paymentModel.getCurrency());
        }else{
            amount.setCurrency(USD);
        }
        amount.setTotal(paymentModel.getAmount());

        refund.setAmount(amount);
        refund.setReason("用户取消订单");

        try {
//            if(request.getSaleId() == null) {
            //注意这段代码，获取saleId
            Payment payment = Payment.get(paypalConfig.apiContext(), oldOrder.getOutTradeNo());
            Transaction transaction = payment.getTransactions().get(0);
            RelatedResources resources = transaction.getRelatedResources().get(0);
            String id = resources.getSale().getId();
//                request.setSaleId(id);
//            }
//
            // ### Api Context
            // Pass in a `ApiContext` object to authenticate
            // the call and to send a unique request id
            // (that ensures idempotency). The SDK generates
            // a request id if you do not pass one explicitly.

            // Refund by posting to the APIService
            // using a valid AccessToken
            Sale sale = new Sale();
            sale.setId(id);
            DetailedRefund res = sale.refund(paypalConfig.apiContext(), refund);
            System.out.println(res);
//            PaypalRefundReturn r = new PaypalRefundReturn();
//            r.setState(res.getState());
//            r.setAmount(res.getAmount().getTotal());
//            r.setCurrency(res.getAmount().getCurrency());
//            return r;
            oldOrder.setState(OrderState.ORDER_CANCEL.getValue());
            oldOrder.setFinishAt(new Timestamp(new Date().getTime()));
            orderMapper.updateById(oldOrder);
            saleDataService.refund(oldOrder);
            stockService.addStock(oldOrder.getGoods());
            return Result.OK();
        } catch (PayPalRESTException | UnsupportedEncodingException e) {
            return Result.error(ResponseState.REFUND_ERROR.getValue(),ResponseState.REFUND_ERROR.getMessage());
        }
    }
}

